﻿using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Application = Autodesk.AutoCAD.ApplicationServices.Application;

namespace DonetArxLib
{
    /// <summary>
    /// 文本合并工具类
    /// 使用限制：只能处理单行文本类型，文本高度相同、文字对齐样式相同，且文字间没有重叠的情况。其它情况需要扩展
    /// </summary>
    internal class TextMergeUtil
    {
        private double LINE_SPACING = 0.7;  // 文本高度差超过 字高*此系数 时，认为是下一行
        private List<ObjectId> _textsIds;

        struct TextPositionInfo
        {
            public ObjectId TextId { get; set; }
            public string TextString { get; set; }
            public double Height { get; set; }
            public Point3d Position { get; set; }
            public Extents3d Extents { get; set; }
        }

        public List<string> GetMergedTextString(List<ObjectId> textEntities)
        {
            List<string> resultStrings = new List<string>();
            if (textEntities == null || textEntities.Count == 0)
                return resultStrings;

            _textsIds = textEntities;
            var infos = GatherTextInfo();
            if (infos == null || infos.Count < 1)
                return resultStrings;

            // 按照高度给文本排序
            infos = infos.OrderByDescending(i => i.Position.Y).ToList();

            // 根据高度差设置，给文本分组，每组认为是同一行的文本
            var lines = GroupTextByHeight(infos);

            // 遍历每一行，按照坐标从左到右排序，拼接字符串，形成行文本
            foreach (var line in lines)
            {
                var lineText = string.Join("", line.OrderBy(t => t.Position.X).Select(t => t.TextString));
                resultStrings.Add(lineText);
            }

            return resultStrings;
        }

        private List<TextPositionInfo> GatherTextInfo()
        {
            var db = HostApplicationServices.WorkingDatabase;
            if (db == null)
                throw new ArgumentNullException("db", "数据库对象不能为空");

            List<TextPositionInfo> result = new List<TextPositionInfo>();
            using (var trans = db.TransactionManager.StartTransaction())
            {
                foreach (var id in _textsIds)
                {
                    var txt = UtilFunc.GetObject(trans, id, OpenMode.ForRead);
                    if (txt != null && txt is DBText dbtxt)
                    {
                        var info = new TextPositionInfo
                        {
                            TextId = id,
                            TextString = dbtxt.TextString,
                            Height = dbtxt.Height,
                            Position = dbtxt.Position,
                            Extents = dbtxt.GeometricExtents
                        };

                        result.Add(info);
                    }
                }
            }

            return result;
        }

        private List<List<TextPositionInfo>> GroupTextByHeight(List<TextPositionInfo> texts)
        {
            if (texts == null || texts.Count < 1)
                throw new ArgumentNullException("texts", "用于分组的文本不可为空");

            List<List<TextPositionInfo>> groups = new List<List<TextPositionInfo>>();

            var currentPos = texts[0].Position.Y;
            var currentGroup = new List<TextPositionInfo>();
            currentGroup.Add(texts[0]);
            groups.Add(currentGroup);
            for (int i=1; i<texts.Count; i++)
            {
                var nextPos = texts[i].Position.Y;
                var heightDiff = currentPos - nextPos;
                if (heightDiff > LINE_SPACING * currentGroup[0].Height)    // 此处使用currentgroup[0].Height 存疑
                {
                    // 认为是下一行
                    currentPos = nextPos;
                    currentGroup = new List<TextPositionInfo>();
                    groups.Add(currentGroup);
                }

                currentGroup.Add(texts[i]);
            }

            return groups;
        }
    }
}
